package com.fingard.dsp.bank.directbank.mybank01;

import com.fingard.constant.Format;
import com.fingard.crypto.SignVerifyHelper;
import com.fingard.crypto.SignatureUtils;
import com.fingard.dsp.bank.directbank.DirectBase;
import com.fingard.text.StringHelper;
import com.fingard.xml.DomHelper;
import com.fingard.xml.XmlTextReader;
import com.fingard.xml.XmlTextWriter;
import org.apache.xml.security.signature.XMLSignature;
import org.w3c.dom.Document;

import javax.net.ssl.*;
import java.io.*;
import java.net.URL;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Date;

/**
 * Created by Ross on 2017-06-06.
 */
public class MYBank01Base extends DirectBase {

    /**
     * 获取字符集
     *
     * @return
     */
    protected String getCharset() {
        return getBankConfig().getCharset("UTF-8");
    }


    protected void writeCommonHeader(XmlTextWriter xmlWriter, MYBank01Header p_bankHeader) throws Exception {

        if (StringHelper.isNullOrEmpty(p_bankHeader.function)) {
            throw new Exception("未赋值function");
        }
        xmlWriter.writeStartDocByDeclaration("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        xmlWriter.writeStartElement("document");
        xmlWriter.writeStartElementByAttr("request", "<request id=\"request\">");
        xmlWriter.writeStartElement("head");
        xmlWriter.writeElementString("version", getBankConfig().getValueAsString("version"));
        xmlWriter.writeElementString("appid", getBankConfig().getValueAsString("appid"));
        xmlWriter.writeElementString("function", p_bankHeader.function);
        if (p_bankHeader.reqTime == null) {
            p_bankHeader.reqTime = new Date();
        }
        xmlWriter.writeElementString("reqTime", Format.DateTime22Format.format(p_bankHeader.reqTime));
        xmlWriter.writeElementString("reqTimeZone", getBankConfig().getValueAsString("reqTimeZone"));
        xmlWriter.writeElementString("reqMsgId", p_bankHeader.reqMsgID);
        xmlWriter.writeElementString("reserve", "");
        xmlWriter.writeElementString("signType", getBankConfig().getValueAsString("signType"));
        xmlWriter.writeElementString("inputCharset", getCharset());
        xmlWriter.writeEndElement();
    }

    protected String signForBody(String p_PlainText, String p_SignFields) throws Exception {
        String cipherText = "";
        if (getBankConfig().getValueAsBool("isBodySign")) {
            WriteBankLogLn2("检测到需进行业务签名...");
            XmlTextReader xmlReader = new XmlTextReader(p_PlainText);
            xmlReader.read("/document/request/body");
            String[] signFields = p_SignFields.split(",");
            String plainText = "";
            for (int i = 0; i < signFields.length; i++) {
                if (i == signFields.length - 1) {
                    plainText = plainText + signFields[i] + "=" + xmlReader.readedXElement.getSingleTextNotNull(signFields[i]);
                } else {
                    plainText = plainText + signFields[i] + "=" + xmlReader.readedXElement.getSingleTextNotNull(signFields[i]) + "||";
                }
            }
            WriteBankLogLn("进行业务签名原字符串为：" + plainText);
            //SignVerifyHelper signVerifyHelper = new SignVerifyHelper();
            try {
                cipherText = SignVerifyHelper.sign(getBankConfig().getValueAsString("pfxConfigPath"), getCharset(), plainText, false);
            } catch (Exception ex) {
                this.WriteBankLogLn(ex);
                throw (ex);
            }
            WriteBankLogLn("进行业务签名后字符串为：" + cipherText);
        }
        return cipherText;
    }

    protected String signForRequest(String p_PlainText) throws Exception {
        String cipherText = "";
        BufferedReader br = null;
        FileReader reader = null;
        try {
            if (getBankConfig().getValueAsBool("isRequestSign")) {
                WriteBankLogLn2("检测到需进行请求签名...");
                WriteBankLogLn("进行请求签名前的字符串为：" + p_PlainText);
                File priKey = new File(getBankConfig().getValueAsString("priKeyPath"));
                StringBuilder result = new StringBuilder();
                reader = new FileReader(priKey);
                br = new BufferedReader(reader);//构造一个BufferedReader类来读取文件
                String s = null;
                while ((s = br.readLine()) != null) {//使用readLine方法，一次读一行
                    result.append("\r\n" + s);
                }
                PrivateKey privateKey = SignatureUtils.getPrivateKey(result.toString());
                Document doc = DomHelper.parseDocumentByString(p_PlainText);
                cipherText = SignatureUtils.signXmlElement(privateKey, doc, "request",
                        XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256, 2);
                WriteBankLogLn("进行请求签名后的字符串为：" + cipherText);
            }
            return cipherText;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            if (br != null) {
                br.close();
            }
            if (reader != null) {
                reader.close();
            }
        }
    }

    protected String[] sendToBank(String p_Req, MYBank01Header p_Header) throws Exception {
        String[] retStr = new String[]{"", ""};
        Document tmpDoc = DomHelper.parseDocumentByString(p_Req);
        if (!p_Header.signValueField.equals("")) {
            String cipherText = signForBody(p_Req, p_Header.signFields);
            tmpDoc.getElementsByTagName(p_Header.signValueField).item(0).setTextContent(cipherText);
        }
        p_Req = signForRequest(DomHelper.toFormatedXML(tmpDoc));

        WriteBankLogLn("2.提交银行的地址：" + bankFront.serverURL);
        WriteBankLogStep2(p_Req);

        URL url = new URL(bankFront.serverURL);
        HttpsURLConnection httpsConn = (HttpsURLConnection) url.openConnection();
        httpsConn.setHostnameVerifier(new HostnameVerifier() {
            public boolean verify(String paramString, SSLSession paramSSLSession) {
                return true;
            }
        });

        //创建SSLContext对象，并使用我们指定的信任管理器初始化
        TrustManager tm = new X509TrustManager() {
            public void checkClientTrusted(X509Certificate[] paramArrayOfX509Certificate,
                                           String paramString) throws CertificateException {
            }

            public void checkServerTrusted(X509Certificate[] paramArrayOfX509Certificate,
                                           String paramString) throws CertificateException {
            }

            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };

        SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
        sslContext.init(null, new TrustManager[]{tm}, new java.security.SecureRandom());

        //从上述SSLContext对象中得到SSLSocketFactory对象
        SSLSocketFactory ssf = sslContext.getSocketFactory();

        //创建HttpsURLConnection对象，并设置其SSLSocketFactory对象
        httpsConn.setSSLSocketFactory(ssf);

        httpsConn.setDoOutput(true);
        httpsConn.setRequestMethod("POST");
        httpsConn.setRequestProperty("Content-Type", "application/xml;charset=UTF-8");
        httpsConn.setRequestProperty("Content-Length", String.valueOf(p_Req.length()));

        OutputStreamWriter out = new OutputStreamWriter(httpsConn.getOutputStream(), "UTF-8");
        out.write(p_Req);
        out.flush();
        out.close();

        BufferedReader reader = new BufferedReader(new InputStreamReader(
                httpsConn.getInputStream(), "UTF-8"));
        String tempLine = "";
        StringBuffer resultBuffer = new StringBuffer();
        while ((tempLine = reader.readLine()) != null) {
            resultBuffer.append(tempLine).append(System.getProperty("line.separator"));
        }

        WriteBankLogStep3(resultBuffer.toString());
        retStr[1] = resultBuffer.toString();
        if (!hasPassedVerify(retStr[1])) {
            retStr[0] = "验签失败";
        }
        return retStr;
    }

    protected Boolean hasPassedVerify(String p_cipherText) throws Exception {
        Boolean isPassed = false;
        BufferedReader br = null;
        FileReader reader = null;
        try {
            if (getBankConfig().getValueAsBool("isResponseNeedVerify")) {
                WriteBankLogLn2("检测到需进行响应验签...");
                Document doc = DomHelper.parseDocumentByString(p_cipherText);
                File pubKey = new File(getBankConfig().getValueAsString("bankPubKeyPath"));
                StringBuilder result = new StringBuilder();
                reader = new FileReader(pubKey);
                br = new BufferedReader(reader);//构造一个BufferedReader类来读取文件
                String s = null;
                while ((s = br.readLine()) != null) {//使用readLine方法，一次读一行
                    result.append("\r\n" + s);
                }
                PublicKey publicKey = SignatureUtils.getPublicKey(result.toString());
                isPassed = SignatureUtils.verifyXmlElement(publicKey, doc);
            } else {
                isPassed = true;
            }
            return isPassed;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            if (br != null) {
                br.close();
            }
            if (reader != null) {
                reader.close();
            }
        }
    }

}
